
#pragma once
#include "jblock.h"


_JIN_BEGIN


template<typename t_Counter>
class CSharedObjectT
{
public:
	CSharedObjectT(void) : m_ref(0)
	{
	}
protected:
	virtual ~CSharedObjectT(void) = 0
	{
	}
public:
	Long AddRef(void)
	{
		return ++m_ref;
	}
	Long Release(void)
	{
		Long ref = --m_ref;
		if (0 == ref)
		{
			delete this;
			return 0;
		}
		return ref;
	}

private:
	t_Counter	m_ref;
};

#if defined(_WIN32) || defined(WIN32)
typedef CSharedObjectT<CCounter>	CSharedObject;
#endif // defined(_WIN32) || defined(WIN32)

template<typename t_Type>
class CSharedObjectPtrT
{
public:
	CSharedObjectPtrT(t_Type* obj = Null)
		: m_obj(obj)
	{
		if (m_obj)
			m_obj->AddRef();
	}
	template<typename t_Rtype>
	CSharedObjectPtrT(t_Rtype* obj)
		: m_obj(dynamic_cast<t_Type*>(obj))
	{
		if (m_obj)
			m_obj->AddRef();
	}
	CSharedObjectPtrT(const CSharedObjectPtrT& rhs)
		: m_obj(rhs.m_obj)
	{
		if (m_obj)
			m_obj->AddRef();
	}
	CSharedObjectPtrT(CSharedObjectPtrT&& rhs)
		: m_obj(rhs.m_obj)
	{
		rhs.m_obj = Null;
	}
	template<typename t_Rtype>
	CSharedObjectPtrT(const CSharedObjectPtrT<t_Rtype>& rhs)
		: m_obj(dynamic_cast<t_Type*>(rhs.m_obj))
	{
		if (m_obj)
			m_obj->AddRef();
	}
	template<typename t_Rtype>
	CSharedObjectPtrT(CSharedObjectPtrT<t_Rtype>&& rhs)
		: m_obj(dynamic_cast<t_Type*>(rhs.m_obj))
	{
		if (m_obj)
			rhs.m_obj = Null;
	}
	virtual ~CSharedObjectPtrT(void)
	{
		if (m_obj)
			m_obj->Release();
		m_obj = Null;
	}

	operator t_Type* (void)
	{
		return m_obj;
	}
	operator const t_Type* (void) const
	{
		return m_obj;
	}

	t_Type* operator -> (void)
	{
		return m_obj;
	}
	const t_Type* operator -> (void) const
	{
		return m_obj;
	}
	t_Type& operator * (void)
	{
		return *m_obj;
	}
	const t_Type& operator * (void) const
	{
		return *m_obj;
	}

	CSharedObjectPtrT& operator = (CSharedObjectPtrT& rhs)
	{
		CSharedObjectPtrT ptr = rhs;

		if (m_obj == ptr.m_obj)
			return *this;

		if (m_obj)
			m_obj->Release();
		m_obj = Null;

		if (ptr.m_obj)
		{
			ptr.m_obj->AddRef();
			m_obj = ptr.m_obj;
		}
		return *this;
	}
	CSharedObjectPtrT& operator = (CSharedObjectPtrT&& rhs)
	{
		if (m_obj)
			m_obj->Release();
		m_obj = rhs.m_obj;
		rhs.m_obj = Null;
		return *this;
	}
	template<typename t_Rtype>
	CSharedObjectPtrT& operator = (CSharedObjectPtrT<t_Rtype>& rhs)
	{
		CSharedObjectPtrT rhs = dynamic_cast<t_Type*>(rhs.m_obj);

		if (m_obj == rhs.m_obj)
			return *this;

		if (m_obj)
			m_obj->Release();
		m_obj = Null;

		if (rhs.m_obj)
		{
			rhs.m_obj->AddRef();
			m_obj = rhs.m_obj;
		}
		return *this;
	}
	template<typename t_Rtype>
	CSharedObjectPtrT& operator = (CSharedObjectPtrT<t_Rtype>&& rhs)
	{
		if (m_obj)
			m_obj->Release();
		m_obj = dynamic_cast<t_Type*>(rhs.m_obj);
		if (m_obj)
			rhs.m_obj = Null;
		return *this;
	}
	CSharedObjectPtrT& operator = (t_Type* obj)
	{
		if (m_obj == obj)
			return *this;

		if (m_obj)
			m_obj->Release();
		m_obj = Null;

		if (obj)
		{
			obj->AddRef();
			m_obj = obj;
		}
		return *this;
	}
	template<typename t_Rtype>
	CSharedObjectPtrT& operator = (t_Rtype* obj)
	{
		t_Type* rhs = dynamic_cast<t_Type*>(obj);

		if (m_obj == rhs)
			return *this;

		if (m_obj)
			m_obj->Release();
		m_obj = Null;

		if (rhs)
		{
			rhs->AddRef();
			m_obj = rhs;
		}
		return *this;
	}

public:
	t_Type*	m_obj;
};


_JIN_END


